from email.header import decode_header
from google.appengine.api import memcache
import re

CHUNK_SIZE=683760 # must be multiple of 77 (76chars + '\n')
mail_re = re.compile(r'\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})\b')
file_re = re.compile('\.[^.]{3}$')
fname_re = re.compile(r'\[([^]]+)]')

class CachedMail(object):
    def __init__(self, message):
        if not hasattr(message, 'subject'):
            self.subject = ''
        else:
            self.subject = ' '.join([s.decode(enc if enc else 'utf-8') for s, enc in decode_header(message.subject)])

        self.to = self._get_mail(message.to)
        self.sender = self._get_mail(message.sender)
        self.domain = self.sender.split('@')[1]
        self.file_name, data, self.encoding = self._get_attachment(message)

        if not self.file_name: return

        self.attachment_size = len(data)
        if self.attachment_to_big(): return

        self.tags = self._get_tags(self.subject)
        self.parts = self._cache_data(self.file_name, data, self.encoding)

    def attachment_to_big(self):
        return self.attachment_size >= 3413333

    def _get_mail(self, s):
        g = mail_re.search(s)
        if not g: 
            log.warn('Unable to extract email from: %s, using full form as email address' % s)
            return s

        return g.groups()[0]

    def _get_attachment(self, message):
        if not hasattr(message, 'attachments'):
            return None, None, None

        if isinstance(message.attachments[0], basestring): att = message.attachments
        else: att = message.attachments[0]

        return self._get_file_name(att[0]), att[1].payload, att[1].encoding

    def _get_file_name(self, fname):
        return file_re.sub('', fname).upper()

    def _get_tags(self, subject):
        match = fname_re.search(subject)
        if not match: return ''
        return ','.join([x.strip() for x in match.groups()[0].lower().capitalize().split(',')])

    def _cache_data(self, file_name, data, encoding):
        cnt = 1
        start = 0
        end = CHUNK_SIZE
        total = len(data) / CHUNK_SIZE 
        if not len(data) % CHUNK_SIZE == 0: total += 1

        while True:
            memcache.set(file_name + '_%s' % cnt, data[start:end], 3600)
            if end >= len(data): break

            start = end
            end += CHUNK_SIZE
            cnt += 1

        return total
